package com.heima.gateway.filter;

import com.heima.common.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author: itheima
 * @create: 2022-03-23 11:35
 */
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器逻辑：校验用户提交的令牌是否有值，是否合法
     *
     * @param exchange 封装请求，响应对象
     * @param chain    过滤器链
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.通过exchange获取请求对象，响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //2.获取客户端请求地址，判断是否为登录请求，如果是直接放行
        String url = request.getURI().getPath();
        if (url.contains("/login")) {
            //管理员登录请求直接放行
            return chain.filter(exchange);
        }

        //3.该请求需要进行拦截，获取客户端提交请求头token 中 令牌值
        String token = request.getHeaders().getFirst("token");
        if (StringUtils.isBlank(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        //4.调用jwt工具类校验令牌合法性（解析成功，是否过期）   成功：放行请求路由到目标微服务   失败：返回错误提示信息
        //4.1 获取JWT中载荷信息（用户信息 userId  userName）
        try {
            Claims claims = AppJwtUtil.getClaimsBody(token);
            //4.2 校验令牌合法性
            int result = AppJwtUtil.verifyToken(claims);
            if (result == -1 || result == 0) {
                Object userId = claims.get("userId");
                Object userName = claims.get("userName");
                //4.3 路由转发请求同时 将用户ID 用户名称 设置到请求头中
                request.mutate().header("userId", userId.toString());
                request.mutate().header("userName", userName.toString());
                return chain.filter(exchange);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("网关令牌校验过滤器异常：{}", e.getMessage());
        }
        //4.4 其他情况直接返回401（未认证）
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();
    }


    /**
     * 过滤器执行顺序  如果存在多个全局过滤 设置执行优先级
     *
     * @return 数字 值越小  优先级越高
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
